/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2020-12-15
 * Version     : v0.1
 * Description : 
 *******************************************************************/
 
/*----------------------------Head file----------------------------*/
#include "string.h"
#include "ls_ble_adpter.h"
#include "ls_ble_custom_api.h"
#include "ls_ble_sdk_config.h"
#include "ls_ble_custom_protocol.h"

#include "osal_ble.h"
#include "sys_task.h"
#include "app_time.h"
#include "app_skip_alg.h"
#include "app_store_mem.h"
#include "app_global_data.h"
#include "app_store_set_info.h"

#define BLE_CUS_API_LOG_EN  1
#if BLE_CUS_API_LOG_EN
#include "ls_ble_log.h"
#define BLE_CUS_API_LOG(...)     LS_BLE_LOG_RAW_INFO(__VA_ARGS__)
#else
#define BLE_CUS_API_LOG(...)
#endif

/*----------------------------macro file---------------------------*/
#define CUS_MEM_RESEND_TIMER_START()        osal_start_timerEx(osalBle_TaskID, APP_BLE_RESEND_EVT, CUSTOM_PKT_RESEND_INV_MS)    //Need about 2 second to send most big packet.
#define CUS_MEM_RESEND_TIMER_STOP()         osal_stop_timerEx(osalBle_TaskID, APP_BLE_RESEND_EVT)

#define CUS_MEM_DELAY_SEND_TIMER_START()    osal_start_timerEx(osalBle_TaskID, APP_BLE_DELAY_SEND_EVT, CUSTOM_PKT_RESEND_INV_MS)    //Need about 2 second to send most big packet.

/*----------------------------type define--------------------------*/

/*----------------------------var define---------------------------*/							
static uint8_t resend_cnt = 0;
static uint8_t pkt_index = 0;
static uint8_t tmp_pkt_index = 0xFF;

/*-------------------------func declaration------------------------*/
extern void set_cur_clr_secs_cnt(void);

/*-----------------------------------------------------------------*/

void ls_ble_custom_callback(ls_ble_cus_cb_evt_param_t* param)
{
    switch(param->evt)
    {
        case LS_BLE_CUS_CB_EVT_DISCONNECT: {
            custom_protocol_disconnect_handle();
        } break;
        
        case LS_BLE_CUS_CB_EVT_IND_ENABLE: {
            g_app_data.sys.ble_conn_type = BLE_CONN_TYPE_PHONE_APP;
            osal_start_timerEx(osalBle_TaskID, APP_BLE_DELAY_UP_BATT, 300);
        } break;
        
        case LS_BLE_CUS_CB_EVT_IND_DISABLE: {
        } break;
        
        /*case LS_BLE_CUS_CB_EVT_IND_COMPLETE: {
            
        } break;*/
        
        case LS_BLE_CUS_CB_EVT_RECEIVE_DATA: {
            ls_ble_custom_rx_payload_handle(param->cmd, param->p_data, param->len);
        } break;
        
        default:
            break;
    }
}


void ls_ble_custom_rx_payload_handle(uint8_t cmd, uint8_t *payload, uint16_t payload_len)
{
    BLE_CUS_API_LOG("ble rx: ");
    for(int i=0;i<payload_len;i++) {
        BLE_CUS_API_LOG("%x, ", payload[i]);
    }
    BLE_CUS_API_LOG("\n");
    switch(cmd)
    {
        case SKIP_CMD_SYNC_TIME: {
            custom_sync_time_t* time = (custom_sync_time_t*)payload;
            BLE_CUS_API_LOG("DL_CMD_SYNC_TIME: %u, %d.\n", time->utc, time->timezone_mins);
            app_set_info_local_timezone_save(time->timezone_mins);
            app_time_uni_utc_set(time->utc);
            set_cur_clr_secs_cnt();
        } break;
        
        case SKIP_CMD_START_SKIP: {
            custom_start_skip_t* start_skip = (custom_start_skip_t*)payload;
            BLE_CUS_API_LOG("DL_CMD_START_SKIP: %u, %d.\n", start_skip->utc, start_skip->mode);
            app_time_uni_utc_set(start_skip->utc);
            set_cur_clr_secs_cnt();
            
            if(start_skip->mode < SKIP_MODE_MAX) {
                //Save not done skip data firstly.
                if(g_app_data.tmp.skip.total_cnts > 0 && false == g_app_data.sys.state.skip_done) {
                    app_skip_result_calc_and_save();
                }
                
                if(SKIP_MODE_COUNTDOWN_TIME == start_skip->mode) {
                    app_set_info_countdown_time_save(start_skip->setting);
                    
                }
                else if(SKIP_MODE_COUNTDOWN_NUM == start_skip->mode) {
                    app_set_info_coutdown_num_save(start_skip->setting);
                }
                
                g_app_data.tmp.tmp_skip_mode = start_skip->mode;
                
                if(start_skip->cnt_down_start > START_SKIP_SECS_MAX_VAL)
                    start_skip->cnt_down_start = START_SKIP_SECS_MAX_VAL;
                
                if(start_skip->cnt_down_start > 0) {
                    g_app_data.tmp.cnt_down_start = start_skip->cnt_down_start;
                    sys_task_msg_send(MSG_TYPE_UI, UI_EVT_SKIP_CNT_DOWN_START);
                }
                else {
                    sys_task_msg_send(MSG_TYPE_UI, UI_EVT_APP_SKIP_MODE_COUNTDOWN_TIME + start_skip->mode);
                }
            }
        } break;
        
        case SKIP_CMD_STOP_SKIP: {
            if(false == g_app_data.sys.state.skip_done && g_app_data.tmp.skip.total_cnts > 0) {
                //Ignore the stop cmd from App if skip have done.
                g_app_data.sys.state.skip_done = true;
                sys_task_msg_send(MSG_TYPE_UI, UI_EVT_DEV_SKIP_DONE);
            }
        } break;
        
        case SKIP_CMD_REALTIME_RET:
        case SKIP_CMD_HISTORY_RET: {
            if(1 == payload_len) {  //Old version
                BLE_CUS_API_LOG("DL_CMD_RSP: %x.\n", payload[0]);
                if(CUSTOM_PROTO_SUCCESS == payload[0]) {	//Get send skip data rsp.
                    ls_ble_custom_mem_resend_timer_stop();
                    app_mem_sent_data_abandon();
                    /* Set next skip data sending into sys evt. If send data here, may cause send indication fail.
                        It may caused by sending data in the same conn interval. */
                    sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_UPLOAD_MEM);
                }
            }
            else if(2 == payload_len) { //New version
                BLE_CUS_API_LOG("DL_CMD_RSP: %d, %d.\n", payload[0], payload[1]);
                if(CUSTOM_PROTO_SUCCESS == payload[0] && pkt_index == payload[1]) {	//Get send skip data rsp.
                    if(tmp_pkt_index != pkt_index) {
                        ls_ble_custom_mem_resend_timer_stop();
                        app_mem_sent_data_abandon();
                        tmp_pkt_index = pkt_index;
                        if(app_mem_unsent_data_size_get() > 0) {
                            /* Set next skip data sending into sys evt. If send data here, may cause send indication fail.
                                It may caused by sending data in the same conn interval. */
                            sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_UPLOAD_MEM);
                        }
                    }
                    else {
                        BLE_CUS_API_LOG("Repeat rsp, we filter it.\n");
                    }
                }
            }
        } break;
        
        case SKIP_CMD_FAC_TEST: {
            BLE_CUS_API_LOG("DL_CMD_FAC_TEST.\n");
            if(0 == payload[0]) {
                sys_task_msg_send(MSG_TYPE_UI, UI_EVT_BOARD_TEST);
            }
            else if(1 == payload[0]) {
                sys_task_msg_send(MSG_TYPE_UI, UI_EVT_DEV_TEST);
            }
        } break;
        
#if(DEV_MAC_BURN_ENABLE)
        case SKIP_CMD_GO_BURN_MODE: {
            BLE_CUS_API_LOG("DL_CMD_GO_BURN_MODE.\n");
            sys_task_msg_send(MSG_TYPE_UI, UI_EVT_ENTER_BURN_MAC_MODE);
        } break;
        
        case SKIP_CMD_BURN_MAC: {
            BLE_CUS_API_LOG("DL_CMD_BURN_MAC: %d.\n", payload_len);
            app_set_info_burn_mac_save(payload, payload_len);
            sys_task_msg_send(MSG_TYPE_UI, UI_EVT_BURN_MAC);
        } break;
#endif

        case SKIP_CMD_DEV_RESET: {
            sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_DEV_RESET);
        } break;
        
        case SKIP_CMD_DEV_REVERT: {
            sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_DEV_REVERT);
        } break;
        case SKIP_CMD_SET_ADV_NAME: {
            uint8_t name_len = payload[0];
            if(true == app_set_info_ble_adv_name_save(&payload[1], name_len)) {
                sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_SET_ADV_NAME);
            }
        } break;

        default:
            break;
        //unknown command
    }
}


void ls_ble_custom_send_msg(uint8_t cmd)
{
    if(BLE_CONN_TYPE_PHONE_APP != g_app_data.sys.ble_conn_type)
        return;

    if(SKIP_CMD_DISP_DATA == cmd && false == custom_send_queue_is_empty())	//Prevent effecting skip memory data send.
        return;

    switch(cmd)
    {
        case SKIP_CMD_DISP_DATA: {
            custom_skip_disp_data_t disp_data;
            disp_data.mode = g_app_data.tmp.skip.mode;
            if(SKIP_MODE_COUNTDOWN_TIME == disp_data.mode) {
                disp_data.setting = g_app_data.user.countdown_time;
            }
            else if(SKIP_MODE_COUNTDOWN_NUM == disp_data.mode) {
                disp_data.setting = g_app_data.user.countdown_num;
            }
            else {
                disp_data.setting = 0;
            }
            disp_data.total_secs = g_app_data.tmp.skip.total_secs;
            disp_data.total_cnts = g_app_data.tmp.skip.total_cnts;
            disp_data.trip_num = g_app_data.tmp.skip.trip_num;
            disp_data.batt_per = g_app_data.batt.disp_percent;
            disp_data.skip_valid_sec = g_app_data.tmp.skip.skip_valid_sec;

            custom_upload_msg(SKIP_CMD_DISP_DATA, (uint8_t*)&disp_data, sizeof(custom_skip_disp_data_t));
        } break;

        case SKIP_CMD_FAC_TEST: {
            BLE_CUS_API_LOG("UP_FAC_TEST_RSP\n");
            uint8_t tx_data = 0;
            custom_upload_msg(SKIP_CMD_FAC_TEST, &tx_data, 1);
        } break;
        
#if(DEV_MAC_BURN_ENABLE)
        case SKIP_CMD_GO_BURN_MODE: {
            uint8_t tx_data = 0;
            custom_upload_msg(SKIP_CMD_GO_BURN_MODE, &tx_data, 1);
        } break;
        
        case SKIP_CMD_BURN_MAC: {
            BLE_CUS_API_LOG("APP_LOG_LVL_INFO, UP_BURN_MAC_RSP\n");
            uint8_t tx_data[DEV_MAC_LEN+1];
            if(DEV_MAC_LEN == app_set_info_burn_mac_get(&tx_data[1])) {
                tx_data[0] = DEV_MAC_VALID;
            }
            else {
                tx_data[0] = DEV_MAC_INVALID;
            }
            custom_upload_msg(SKIP_CMD_BURN_MAC, tx_data, DEV_MAC_LEN+1);
        } break;
#endif

        case SKIP_CMD_DEV_RESET: {
            uint8_t tx_data = 0;
            custom_upload_msg(SKIP_CMD_DEV_RESET, &tx_data, 1);
        } break;
        
        case SKIP_CMD_DEV_REVERT: {
            uint8_t tx_data = 0;
            custom_upload_msg(SKIP_CMD_DEV_REVERT, &tx_data, 1);
        } break;
        
        case SKIP_CMD_SET_ADV_NAME: {
            uint8_t tx_data[APP_DEVICE_NAME_MAX_LEN+1];
            uint8_t name_len = app_set_info_ble_adv_name_get(&tx_data[1]);
            tx_data[0] = name_len;
            custom_upload_msg(SKIP_CMD_SET_ADV_NAME, tx_data, name_len+1);
        } break;

        default:
            break;
    }
}


bool ls_ble_custom_upload_unsent_skip_ret(bool increase)
{
    uint32_t unsent_size = 0;
    uint8_t cmd = SKIP_CMD_NULL;
    uint8_t payload[CUSTOM_TX_PKT_PAYLOAD_MAX_SIZE];

    if(BLE_CONN_TYPE_PHONE_APP != g_app_data.sys.ble_conn_type)
        return false;

    unsent_size = app_mem_unsent_data_size_get();
    BLE_CUS_API_LOG("unsent_size: %d.\n", unsent_size);
    if(unsent_size <= 0) {
        return false;
    }
    
    BLE_CUS_API_LOG("ls_ble_custom_upload_unsent_skip_ret.\n");

    memset(payload, 0, sizeof(payload));
    app_mem_unsent_skip_data_read(payload, sizeof(skip_packet_t));
    skip_packet_t* skip_pack = (skip_packet_t*)payload;

#if (LS_BLE_LOG_ENABLE && DEBUG_INFO == 1)
    BLE_CUS_API_LOG("utc: %d.\n", skip_pack->start_utc);
    BLE_CUS_API_LOG("skip_cnt: %d.\n", skip_pack->total_cnts);
    BLE_CUS_API_LOG("skip_secs: %d.\n", skip_pack->total_secs);
    /*for(uint8_t i=0;i<=skip_pack->trip_num;i++) {
        BLE_CUS_API_LOG("c_sec: %d.\n", skip_pack->group[i].skip_sec);
        BLE_CUS_API_LOG("c_cnt: %d.\n", skip_pack->group[i].skip_cnt);
    }*/
#endif

    if(unsent_size <= sizeof(save_skip_packet_t)) {
        cmd = SKIP_CMD_REALTIME_RET;
    }
    else {
        cmd = SKIP_CMD_HISTORY_RET;
    }
    //BLE_CUS_API_LOG("len: %d, %d\n", sizeof(skip_packet_t) - SKIP_GROUP_MAX_NUM*sizeof(skip_group_t), skip_pack->trip_num);
    uint16_t payload_len = (sizeof(skip_packet_t) - SKIP_GROUP_MAX_NUM*sizeof(skip_group_t) + (skip_pack->trip_num+1)*sizeof(skip_group_t) + 1);	
    memcpy(&payload[payload_len-3], (uint8_t*)&skip_pack->skip_valid_sec, sizeof(uint16_t)); //Patch for master calorie algorithm.
    if(increase) {
        pkt_index++;
        LOG("pkt_index increase: %d.\n", pkt_index);
        payload[payload_len - 1] = pkt_index;  //Patch for increase index.
    }
    else {
        payload[payload_len - 1] = pkt_index;  //Patch for increase index.
    }

    custom_protocol_send_queue_clear();         //Clear queue, or device may not recognize response correctly from master.
    if(false == custom_upload_msg(cmd, payload, payload_len)) {
        LOG("custom_upload_mem fail.\n");
        return false;
    }

    return true;
}


void ls_ble_custom_mem_delay_send_timer_start(void)
{
    resend_cnt = 0;
    CUS_MEM_DELAY_SEND_TIMER_START();
    BLE_CUS_API_LOG("app_skip_mem_delay_send_timer_start.\n");
}


void ls_ble_custom_mem_resend_timer_start(void)
{
    resend_cnt = 0;
    CUS_MEM_RESEND_TIMER_START();
    BLE_CUS_API_LOG("app_skip_mem_resend_timer_start.\n");
}


void ls_ble_custom_mem_resend_timer_stop(void)
{
    CUS_MEM_RESEND_TIMER_STOP();
}


void ls_ble_custom_mem_resend_timeout_handle(void)
{
    resend_cnt++;
    if(resend_cnt < 3) {
        if(true == ls_ble_custom_upload_unsent_skip_ret(false)) {
            BLE_CUS_API_LOG("resend_cnt: %d.\n", resend_cnt);
            CUS_MEM_RESEND_TIMER_START();
        }
    }
}
